Deduplikasi Sumber Daya React Suspense: Mencegah Permintaan Duplikat | MLOG | MLOG
Bahasa Indonesia
Pelajari cara mencegah permintaan pengambilan data duplikat di aplikasi React menggunakan Suspense dan teknik deduplikasi sumber daya untuk meningkatkan performa dan efisiensi.
Deduplikasi Sumber Daya React Suspense: Mencegah Permintaan Duplikat
React Suspense telah merevolusi cara kita menangani pengambilan data asinkron dalam aplikasi React. Dengan memungkinkan komponen untuk "menunda" rendering hingga datanya tersedia, ini memberikan pendekatan yang lebih bersih dan lebih deklaratif dibandingkan dengan manajemen status pemuatan tradisional. Namun, tantangan umum muncul ketika beberapa komponen mencoba mengambil sumber daya yang sama secara bersamaan, yang mengarah pada permintaan duplikat dan potensi hambatan performa. Artikel ini mengeksplorasi masalah permintaan duplikat di React Suspense dan memberikan solusi praktis menggunakan teknik deduplikasi sumber daya.
Memahami Masalah: Skenario Permintaan Duplikat
Bayangkan sebuah skenario di mana beberapa komponen di satu halaman perlu menampilkan data profil pengguna yang sama. Tanpa manajemen yang tepat, setiap komponen mungkin memulai permintaannya sendiri untuk mengambil profil pengguna, yang mengakibatkan panggilan jaringan yang berlebihan. Ini membuang-buang bandwidth, meningkatkan beban server, dan pada akhirnya menurunkan pengalaman pengguna.
Berikut adalah contoh kode sederhana untuk mengilustrasikan masalah ini:
import React, { Suspense } from 'react';
const fetchUser = (userId) => {
console.log(`Mengambil pengguna dengan ID: ${userId}`); // Simulasi permintaan jaringan
return new Promise(resolve => {
setTimeout(() => {
resolve({ id: userId, name: `Pengguna ${userId}`, email: `user${userId}@example.com` });
}, 1000); // Simulasi latensi jaringan
});
};
const UserResource = (userId) => {
let promise = null;
let status = 'pending'; // pending, success, error
let result;
const suspender = fetchUser(userId).then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
}
return result;
},
};
};
const UserProfile = ({ userId }) => {
const user = UserResource(userId).read();
return (
Dalam contoh ini, kedua komponen UserProfile dan UserDetails mencoba mengambil data pengguna yang sama menggunakan UserResource. Jika Anda menjalankan kode ini, Anda akan melihat bahwa Mengambil pengguna dengan ID: 1 dicatat dua kali, yang menunjukkan dua permintaan terpisah.
Teknik Deduplikasi Sumber Daya
Untuk mencegah permintaan duplikat, kita dapat mengimplementasikan deduplikasi sumber daya. Ini melibatkan memastikan bahwa hanya satu permintaan yang dibuat untuk sumber daya tertentu, dan hasilnya dibagikan di antara semua komponen yang membutuhkannya. Beberapa teknik dapat digunakan untuk mencapai ini.
1. Menyimpan Promise dalam Cache
Pendekatan yang paling sederhana adalah dengan menyimpan promise yang dikembalikan oleh fungsi pengambilan data dalam cache. Ini memastikan bahwa jika sumber daya yang sama diminta lagi saat permintaan asli masih dalam proses, promise yang ada akan dikembalikan alih-alih membuat yang baru.
Berikut cara Anda dapat memodifikasi UserResource untuk mengimplementasikan caching promise:
import React, { Suspense } from 'react';
const fetchUser = (userId) => {
console.log(`Mengambil pengguna dengan ID: ${userId}`); // Simulasi permintaan jaringan
return new Promise(resolve => {
setTimeout(() => {
resolve({ id: userId, name: `Pengguna ${userId}`, email: `user${userId}@example.com` });
}, 1000); // Simulasi latensi jaringan
});
};
const cache = {}; // Cache sederhana
const UserResource = (userId) => {
if (!cache[userId]) {
let promise = null;
let status = 'pending'; // pending, success, error
let result;
const suspender = fetchUser(userId).then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
cache[userId] = {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
}
return result;
},
};
}
return cache[userId];
};
const UserProfile = ({ userId }) => {
const user = UserResource(userId).read();
return (
Sekarang, UserResource akan memeriksa apakah sumber daya sudah ada di dalam cache. Jika ya, sumber daya yang di-cache akan dikembalikan. Jika tidak, permintaan baru akan dimulai, dan promise yang dihasilkan akan disimpan di dalam cache. Ini memastikan bahwa hanya satu permintaan yang dibuat untuk setiap userId yang unik.
2. Menggunakan Library Caching Khusus (misalnya, `lru-cache`)
Untuk skenario caching yang lebih kompleks, pertimbangkan untuk menggunakan library caching khusus seperti lru-cache atau sejenisnya. Library ini menyediakan fitur seperti penghapusan cache berdasarkan Least Recently Used (LRU) atau kebijakan lain, yang bisa sangat penting untuk mengelola penggunaan memori, terutama saat berhadapan dengan sejumlah besar sumber daya.
Pertama, instal library:
npm install lru-cache
Kemudian, integrasikan ke dalam UserResource Anda:
import React, { Suspense } from 'react';
import LRUCache from 'lru-cache';
const fetchUser = (userId) => {
console.log(`Mengambil pengguna dengan ID: ${userId}`); // Simulasi permintaan jaringan
return new Promise(resolve => {
setTimeout(() => {
resolve({ id: userId, name: `Pengguna ${userId}`, email: `user${userId}@example.com` });
}, 1000); // Simulasi latensi jaringan
});
};
const cache = new LRUCache({
max: 100, // Jumlah maksimum item dalam cache
ttl: 60000, // Waktu hidup dalam milidetik (1 menit)
});
const UserResource = (userId) => {
if (!cache.has(userId)) {
let promise = null;
let status = 'pending'; // pending, success, error
let result;
const suspender = fetchUser(userId).then(
(r) => {
status = 'success';
result = r;
cache.set(userId, {
read() {
return result;
},
});
},
(e) => {
status = 'error';
result = e;
cache.set(userId, {
read() {
throw result;
},
});
}
);
cache.set(userId, {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
}
return result;
}
});
}
return cache.get(userId);
};
const UserProfile = ({ userId }) => {
const user = UserResource(userId).read();
return (
Pendekatan ini memberikan lebih banyak kontrol atas ukuran dan kebijakan kedaluwarsa cache.
3. Menggabungkan Permintaan (Request Coalescing) dengan Library seperti `axios-extensions`
Library seperti axios-extensions menawarkan fitur yang lebih canggih seperti request coalescing. Request coalescing menggabungkan beberapa permintaan identik menjadi satu permintaan tunggal, yang lebih lanjut mengoptimalkan penggunaan jaringan. Ini sangat berguna dalam skenario di mana permintaan dimulai sangat berdekatan dalam waktu.
Pertama, instal library:
npm install axios axios-extensions
Kemudian, konfigurasikan Axios dengan adapter cache yang disediakan oleh axios-extensions.
Contoh penggunaan `axios-extensions` dan membuat sumber daya:
import React, { Suspense } from 'react';
import axios from 'axios';
import { cacheAdapterEnhancer, throttleAdapterEnhancer } from 'axios-extensions';
const instance = axios.create({
baseURL: 'https://api.example.com', // Ganti dengan endpoint API Anda
adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: true }),
});
const fetchUser = async (userId) => {
console.log(`Mengambil pengguna dengan ID: ${userId}`); // Simulasi permintaan jaringan
const response = await instance.get(`/users/${userId}`);
return response.data;
};
const UserResource = (userId) => {
let promise = null;
let status = 'pending'; // pending, success, error
let result;
const suspender = fetchUser(userId).then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
}
return result;
},
};
};
const UserProfile = ({ userId }) => {
const user = UserResource(userId).read();
return (
Ini mengonfigurasi Axios untuk menggunakan adapter cache, secara otomatis menyimpan respons dalam cache berdasarkan konfigurasi permintaan. Fungsi cacheAdapterEnhancer menyediakan opsi untuk mengonfigurasi cache, seperti menetapkan ukuran cache maksimum atau waktu kedaluwarsa. throttleAdapterEnhancer juga dapat digunakan untuk membatasi jumlah permintaan yang dibuat ke server dalam periode waktu tertentu, yang lebih lanjut mengoptimalkan performa.
Praktik Terbaik untuk Deduplikasi Sumber Daya
Pusatkan Manajemen Sumber Daya: Buat modul atau layanan khusus untuk mengelola sumber daya. Ini mendorong penggunaan ulang kode dan mempermudah implementasi strategi deduplikasi.
Gunakan Kunci Unik: Pastikan kunci caching Anda unik dan secara akurat mewakili sumber daya yang diambil. Ini sangat penting untuk menghindari tabrakan cache.
Pertimbangkan Invalidasi Cache: Implementasikan mekanisme untuk membatalkan cache ketika data berubah. Ini memastikan bahwa komponen Anda selalu menampilkan informasi yang paling mutakhir. Teknik umum termasuk menggunakan webhook atau membatalkan cache secara manual saat pembaruan terjadi.
Pantau Performa Cache: Lacak tingkat cache hit dan waktu respons untuk mengidentifikasi potensi hambatan performa. Sesuaikan strategi caching Anda sesuai kebutuhan untuk mengoptimalkan performa.
Implementasikan Penanganan Kesalahan: Pastikan logika caching Anda menyertakan penanganan kesalahan yang kuat. Ini mencegah kesalahan menyebar ke komponen Anda dan memberikan pengalaman pengguna yang lebih baik. Pertimbangkan strategi untuk mencoba kembali permintaan yang gagal atau menampilkan konten fallback.
Gunakan AbortController: Jika sebuah komponen dilepas (unmount) sebelum data diambil, gunakan `AbortController` untuk membatalkan permintaan guna mencegah pekerjaan yang tidak perlu dan potensi kebocoran memori.
Pertimbangan Global untuk Pengambilan Data dan Deduplikasi
Saat merancang strategi pengambilan data untuk audiens global, beberapa faktor ikut berperan:
Content Delivery Networks (CDNs): Manfaatkan CDN untuk mendistribusikan aset statis dan respons API Anda di lokasi yang beragam secara geografis. Ini mengurangi latensi bagi pengguna yang mengakses aplikasi Anda dari berbagai belahan dunia.
Data yang Dilokalkan: Implementasikan strategi untuk menyajikan data yang dilokalkan berdasarkan lokasi atau preferensi bahasa pengguna. Ini mungkin melibatkan penggunaan endpoint API yang berbeda atau menerapkan transformasi pada data di sisi server atau klien. Misalnya, situs e-commerce Eropa mungkin menampilkan harga dalam Euro, sementara situs yang sama yang dilihat dari Amerika Serikat mungkin menampilkan harga dalam Dolar AS.
Zona Waktu: Perhatikan zona waktu saat menampilkan tanggal dan waktu. Gunakan library pemformatan dan konversi yang sesuai untuk memastikan bahwa waktu ditampilkan dengan benar untuk setiap pengguna.
Konversi Mata Uang: Saat berurusan dengan data keuangan, gunakan API konversi mata uang yang andal untuk menampilkan harga dalam mata uang lokal pengguna. Pertimbangkan untuk menyediakan opsi bagi pengguna untuk beralih antara mata uang yang berbeda.
Aksesibilitas: Pastikan strategi pengambilan data Anda dapat diakses oleh pengguna dengan disabilitas. Ini termasuk menyediakan atribut ARIA yang sesuai untuk indikator pemuatan dan pesan kesalahan.
Privasi Data: Patuhi peraturan privasi data seperti GDPR dan CCPA saat mengumpulkan dan memproses data pengguna. Terapkan langkah-langkah keamanan yang sesuai untuk melindungi informasi pengguna.
Sebagai contoh, situs web pemesanan perjalanan yang menargetkan audiens global mungkin menggunakan CDN untuk menyajikan data ketersediaan penerbangan dan hotel dari server yang berlokasi di berbagai wilayah. Situs web tersebut juga akan menggunakan API konversi mata uang untuk menampilkan harga dalam mata uang lokal pengguna dan menyediakan opsi untuk memfilter hasil pencarian berdasarkan preferensi bahasa.
Kesimpulan
Deduplikasi sumber daya adalah teknik optimasi penting untuk aplikasi React yang menggunakan Suspense. Dengan mencegah permintaan pengambilan data duplikat, Anda dapat secara signifikan meningkatkan performa, mengurangi beban server, dan meningkatkan pengalaman pengguna. Baik Anda memilih untuk mengimplementasikan cache promise sederhana atau memanfaatkan library yang lebih canggih seperti lru-cache atau axios-extensions, kuncinya adalah memahami prinsip-prinsip yang mendasarinya dan memilih solusi yang paling sesuai dengan kebutuhan spesifik Anda. Ingatlah untuk mempertimbangkan faktor-faktor global seperti CDN, lokalisasi, dan aksesibilitas saat merancang strategi pengambilan data Anda untuk audiens yang beragam. Dengan menerapkan praktik terbaik ini, Anda dapat membangun aplikasi React yang lebih cepat, lebih efisien, dan lebih ramah pengguna.